import json
import logging
import time

import hashlib
import hmac
import requests.auth
import urllib.parse

from coin.exchange.base.kr_rest.auth_base import AuthKey
from coin.exchange.base.kr_rest.rest_client_base import RestUpdate
from coin.exchange.util.rate_limit import RateLimiter


PREX_API_URL = 'api.aqx.com'


def generate_api_key_signature(secret, verb, url, expires, data):
  parsed_url = urllib.parse.urlparse(url)
  path = parsed_url.path
  if parsed_url.query:
      path = path + '?' + parsed_url.query
  if isinstance(data, (bytes, bytearray)):
      data = data.decode('utf8')
  message = verb + path + str(expires) + data
  signature = hmac.new(
      bytes(secret, 'utf8'), bytes(message, 'utf8'), digestmod=hashlib.sha256)
  return signature.hexdigest()


class PrexAuth(requests.auth.AuthBase):
  def __init__(self, key_file):
    self._key = AuthKey.from_file(key_file)

  def _gen_signature(self, data):
    signature = hmac.new(self._key.secret_key_bytes, data, digestmod=hashlib.sha256)
    return signature.hexidgest()

  def __call__(self, req):
    expires = int(round(time.time()) + 5)
    req.headers['api-expires'] = str(expires)
    req.headers['api-key'] = self._key.access_key
    req.headers['api-signature'] = generate_api_key_signature(
        self._key.secret_key, req.method, req.url, expires, req.body or '')
    return req


class PrexFuturesSyncQueryer(object):
  def __init__(self, key_file, *, api_host=None, timeout=10):
    self._timeout = timeout
    self._auth = PrexAuth(key_file)
    self._api_host = "https://" + (api_host or PREX_API_URL)
    self.rate_limit = RateLimiter(20, 1)
    self._logger = logging.getLogger(__name__)

  def auth_request(self, method, path, params):
    assert method in ('GET', 'PUT', 'POST', 'DELETE'), method
    url = urllib.parse.urljoin(self._api_host, path)
    response = None
    try:
      response = requests.request(method,
                                  url,
                                  params=params,
                                  auth=self._auth,
                                  timeout=self._timeout)
      content = response.json()
      return content
    except requests.exceptions.RequestException as e:
      self._logger.exception('RequestException: %s', e)
      raise
    except json.JSONDecodeError as e:
      self._logger.exception('JsonDecodeException: %s\n %s', response.content, e)
      raise
    except Exception as e:
      self._logger.exception('Unknown exception, %s', e)
      raise

  def _query_nocheck(self, method, path, params):
    req_timestamp = time.time()
    content = self.auth_request(method, path, params)
    res_timestamp = time.time()
    status = requests.codes.ok
    update = RestUpdate(req_timestamp, res_timestamp, content, status)
    return update

  def query(self, method, path, params=None, disable_rate_limit=False):
    if not disable_rate_limit:
      while not self.rate_limit.check():
        time.sleep(0.1)
    else:
      self.rate_limit.check()
    return self._query_nocheck(method, path, params)


class PrexFuturesNativePrivateClient(object):
  def __init__(
      self,
      *,
      key_file,
      api_host=None,
      timeout=10):
    self._auth_queryer = PrexFuturesSyncQueryer(
        key_file, api_host=api_host, timeout=timeout)

  def _query(self, method, path, params=None):
    return self._auth_queryer.query(method, path, params=params)

  def query_wallet(self):
    method = 'GET'
    path = '/api/v1/wallet'
    update = self._query(method, path)
    return update

  def query_margin(self):
    method = 'GET'
    path = '/api/v1/margin'
    update = self._query(method, path)
    return update

  def query_position(self):
    method = 'GET'
    path = '/api/v1/position'
    update = self._query(method, path)
    return update


if __name__ == "__main__":
  client = PrexFuturesNativePrivateClient(
      key_file='../../coin_key/view/xunke00/prex/view_key.json')
  print(client.query_wallet())
  print(client.query_margin())
  print(client.query_position())
